#include "./BSP/BEEP/beep.h"

#if !USE_ACTIVE_BEEP
/* -------------------------------------------- 全局变量定义 -------------------------------------------- */

TIM_HandleTypeDef g_beep_tim_handler;        /* 蜂鸣器定时器句柄 */
TIM_OC_InitTypeDef g_beep_tim_oc_handler;    /* 蜂鸣器定时器通道句柄 */
uint8_t g_beep_volume = 100;                 /* 蜂鸣器音量，默认100%音量（对应50%占空比，最响） */
uint32_t g_beep_frequency = 2000;            /* 蜂鸣器频率，默认2kHz */
uint8_t g_beep_status = 0;                   /* 蜂鸣器状态，0:关闭 1:开启 */

#endif

/* -------------------------------------------- 蜂鸣器IO初始化 ------------------------------------------- */

/**
 * @brief       初始化蜂鸣器
 * @param       无
 * @retval      无
 * @note        根据USE_ACTIVE_BEEP宏定义选择初始化方式
 *              有源蜂鸣器：配置GPIO为输出模式
 *              无源蜂鸣器：配置GPIO为PWM模式，初始化定时器
 */
void beep_init(void)
{
#if USE_ACTIVE_BEEP
    /* 有源蜂鸣器初始化 */
    GPIO_InitTypeDef gpio_init_struct;
    
    BEEP_GPIO_CLK_ENABLE();                             /* 蜂鸣器时钟使能 */

    gpio_init_struct.Pin = BEEP_GPIO_PIN;               /* 蜂鸣器引脚 */
    gpio_init_struct.Mode = GPIO_MODE_OUTPUT_PP;        /* 推挽输出 */
    gpio_init_struct.Pull = GPIO_PULLUP;                /* 上拉 */
    gpio_init_struct.Speed = GPIO_SPEED_FREQ_HIGH;      /* 高速 */
    HAL_GPIO_Init(BEEP_GPIO_PORT, &gpio_init_struct);   /* 初始化蜂鸣器引脚 */

    BEEP(0);                                            /* 关闭蜂鸣器 */

#else
    /* 无源蜂鸣器初始化 */
    /* 注意：GPIO配置通常在HAL_TIM_PWM_MspInit回调函数中完成，此处为了避免与别的模块冲突，所以单独配置 */
    GPIO_InitTypeDef gpio_init_struct;
    
    /* 使能时钟 */
    BEEP_GPIO_CLK_ENABLE();                             /* 蜂鸣器GPIO时钟使能 */
    BEEP_TIMX_CLK_ENABLE();                             /* 蜂鸣器定时器时钟使能 */
    
    /* 配置蜂鸣器引脚为PWM输出模式 */
    gpio_init_struct.Pin = BEEP_GPIO_PIN;               /* 蜂鸣器引脚 */
    gpio_init_struct.Mode = GPIO_MODE_AF_PP;            /* 复用推挽输出 */
    gpio_init_struct.Pull = GPIO_PULLUP;                /* 上拉 */
    gpio_init_struct.Speed = GPIO_SPEED_FREQ_HIGH;      /* 高速 */
    gpio_init_struct.Alternate = BEEP_GPIO_AFTIMX;      /* 复用为定时器功能 */
    HAL_GPIO_Init(BEEP_GPIO_PORT, &gpio_init_struct);   /* 初始化蜂鸣器引脚为PWM输出 */
    
    /* 初始化PWM定时器 */
    beep_pwm_init(g_beep_frequency, g_beep_volume);     /* 初始化PWM，默认频率和音量 */
    
    /* 确保蜂鸣器关闭 */
    beep_stop();
}
#endif

#if !USE_ACTIVE_BEEP
/* -------------------------------------------- 定时器底层初始化回调函数 -------------------------------------------- */

/**
 * @brief      定时器PWM底层初始化回调函数
 * @param[in]  htim        定时器句柄指针
 *
 * @note       该函数会被HAL_TIM_PWM_Init()自动调用
 * @retval     无
 */
//void HAL_TIM_PWM_MspInit(TIM_HandleTypeDef *htim)
//{
//    GPIO_InitTypeDef gpio_init_struct;

//    if (htim->Instance == BEEP_TIMX)
//    {
//        BEEP_TIMX_CLK_ENABLE();           /* 使能蜂鸣器引脚定时器时钟 */
//        
//        /* 初始化蜂鸣器PWM引脚 */
//        BEEP_GPIO_CLK_ENABLE();
//        gpio_init_struct.Pin = BEEP_GPIO_PIN;
//        gpio_init_struct.Mode = GPIO_MODE_AF_PP;
//        gpio_init_struct.Pull = GPIO_PULLUP;
//        gpio_init_struct.Speed = GPIO_SPEED_FREQ_HIGH;
//        gpio_init_struct.Alternate = BEEP_GPIO_AFTIMX;
//        HAL_GPIO_Init(BEEP_GPIO_PORT, &gpio_init_struct);
//    }
//}
#endif

#if !USE_ACTIVE_BEEP
/* -------------------------------------------- 无源蜂鸣器PWM控制函数 -------------------------------------------- */

/**
 * @brief       蜂鸣器PWM定时器初始化函数
 * @param[in]   freq        蜂鸣器频率，单位Hz
 * @param[in]   volume      蜂鸣器音量，范围0-100
 * @note        定时器的时钟来自APB1，当APB1分频时，定时器频率自动翻倍
 *              定时器溢出时间计算方法: Tout = ((arr + 1) * (psc + 1)) / Ft us.
 *              Ft = 定时器工作频率，单位: MHz
 * @retval      无
 */
void beep_pwm_init(uint32_t freq, uint8_t volume)
{
    uint32_t timer_clock = 84000000;  /* TIM4时钟频率84MHz (APB1 * 2) */
    uint32_t arr, psc;
    
    /* 计算定时器参数 */
    /* 频率公式: freq = timer_clock / ((psc + 1) * (arr + 1)) */
    /* 固定ARR=999以获得1000级PWM分辨率，然后计算PSC */
    arr = 999;
    psc = (timer_clock / (freq * (arr + 1))) - 1;
    
    /* 限制PSC范围，防止超出16位寄存器 */
    if (psc > 65535) psc = 65535;
    
    /* 配置定时器基本参数 */
    g_beep_tim_handler.Instance = BEEP_TIMX;                        /* 蜂鸣器定时器 */
    g_beep_tim_handler.Init.Prescaler = psc;                        /* 预分频器 */
    g_beep_tim_handler.Init.CounterMode = TIM_COUNTERMODE_UP;       /* 向上计数模式 */
    g_beep_tim_handler.Init.Period = arr;                           /* 自动重装载值 */
    g_beep_tim_handler.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1; /* 时钟分频 */
    g_beep_tim_handler.Init.RepetitionCounter = 0;                  /* 重复计数器 */
    g_beep_tim_handler.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE; /* 自动重装载预装载 */
    
    HAL_TIM_PWM_Init(&g_beep_tim_handler);                          /* 初始化PWM定时器 */
    
    /* 配置PWM通道参数 */
    g_beep_tim_oc_handler.OCMode = TIM_OCMODE_PWM1;                 /* PWM模式1: CNT<CCR时输出有效电平 */
    g_beep_tim_oc_handler.Pulse = 0;                                /* 初始占空比为0，蜂鸣器关闭 */
    g_beep_tim_oc_handler.OCPolarity = TIM_OCPOLARITY_HIGH;         /* 输出极性为高电平有效 */
    g_beep_tim_oc_handler.OCFastMode = TIM_OCFAST_DISABLE;          /* 快速模式禁用 */
    
    HAL_TIM_PWM_ConfigChannel(&g_beep_tim_handler, &g_beep_tim_oc_handler, BEEP_TIMX_CHY);  /* 配置蜂鸣器定时器通道 */
    
    /* 设置初始音量 */
    beep_set_volume(volume);
}

/**
 * @brief       启动蜂鸣器
 * @param       无
 * @retval      无
 * @note        启动PWM输出，蜂鸣器开始发声
 */
void beep_start(void)
{
    if (g_beep_status == 0)  /* 如果蜂鸣器当前是关闭状态 */
    {
        HAL_TIM_PWM_Start(&g_beep_tim_handler, BEEP_TIMX_CHY);  /* 启动PWM输出 */
        g_beep_status = 1;   /* 设置蜂鸣器状态为开启 */
    }
}

/**
 * @brief       停止蜂鸣器
 * @param       无
 * @retval      无
 * @note        停止PWM输出，蜂鸣器停止发声
 */
void beep_stop(void)
{
    if (g_beep_status == 1)  /* 如果蜂鸣器当前是开启状态 */
    {
        HAL_TIM_PWM_Stop(&g_beep_tim_handler, BEEP_TIMX_CHY);   /* 停止PWM输出 */
        g_beep_status = 0;   /* 设置蜂鸣器状态为关闭 */
    }
}

/**
 * @brief       切换蜂鸣器状态
 * @param       无
 * @retval      无
 * @note        如果蜂鸣器开启则关闭，如果关闭则开启
 */
void beep_toggle(void)
{
    if (g_beep_status == 1)
    {
        beep_stop();
    }
    else
    {
        beep_start();
    }
}

/**
 * @brief       设置蜂鸣器频率
 * @param[in]   freq        蜂鸣器频率，单位Hz，建议范围100-8000Hz
 * @retval      无
 * @note        频率改变时会重新配置定时器参数
 */
void beep_set_frequency(uint32_t freq)
{
    uint32_t timer_clock = 84000000;  /* TIM4时钟频率84MHz */
    uint32_t arr, psc;
    uint8_t current_status = g_beep_status;
    
    /* 限制频率范围 */
    if (freq < 100) freq = 100;
    if (freq > 8000) freq = 8000;
    
    /* 保存新频率 */
    g_beep_frequency = freq;
    
    /* 如果蜂鸣器正在运行，先停止 */
    if (current_status)
    {
        beep_stop();
    }
    
    /* 重新计算定时器参数 */
    arr = 999;
    psc = (timer_clock / (freq * (arr + 1))) - 1;
    if (psc > 65535) psc = 65535;
    
    /* 更新定时器参数 */
    __HAL_TIM_SET_PRESCALER(&g_beep_tim_handler, psc);
    __HAL_TIM_SET_AUTORELOAD(&g_beep_tim_handler, arr);
    
    /* 如果之前是开启状态，重新启动 */
    if (current_status)
    {
        beep_start();
    }
}

/**
 * @brief       设置蜂鸣器音量
 * @param[in]   volume      蜂鸣器音量，范围0-100
 * @retval      无
 * @note        通过调整PWM占空比来控制音量
 *              方波在50%占空比时能量最大，声音最响，因此100%音量对应50%占空比
 *              当音量大于0时自动启动蜂鸣器，当音量为0时自动关闭蜂鸣器
 */
void beep_set_volume(uint8_t volume)
{
    uint32_t pulse;
    
    /* 限制音量范围 */
    if (volume > 100) volume = 100;
    
    /* 保存新音量 */
    g_beep_volume = volume;
    
    /* 智能控制蜂鸣器开关状态 */
    if (volume > 0)
    {
        /* 音量大于0，启动蜂鸣器 */
        if (g_beep_status == 0)
        {
            beep_start();
        }
        
        /* 计算PWM占空比值 - 方波在50%占空比时能量最大，因此100%音量对应50%占空比 */
        uint32_t arr = __HAL_TIM_GET_AUTORELOAD(&g_beep_tim_handler);
        pulse = (volume * (arr + 1)) / 200;  /* 音量除以2作为占空比，避免整数除法精度丢失 */
        
        /* 更新PWM占空比 */
        __HAL_TIM_SET_COMPARE(&g_beep_tim_handler, BEEP_TIMX_CHY, pulse);
    }
    else
    {
        /* 音量为0，关闭蜂鸣器 */
        beep_stop();
    }
}

#endif
